﻿namespace ElisVK.ViewModels
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Timers;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using System.Windows.Input;
    using System.Windows.Media;
    using Data;
    using Data.AudioSources;
    using Utils;
    using Utils.HotKeys;
    using TaskbarNotification;

    public enum Pages
    {
        MainPage,
        SettingsPage
    }

    public enum NotificationActions
    {
        Play,
        Pause,
        Volume,
        Shuffle,
        Remove,
        Add,
        Info
    }

    public class ElisVKViewModel : BindableObject, IDisposable
    {
        #region Fields

        private bool _isPlaying;

        private bool _isShuffleOn;

        private Audio _selectedAudio;

        private ObservableCollection<Audio> _audios;

        private UserInfo _friend;

        private ObservableCollection<UserInfo> _friends;

        private AudioSource _audioSource;

        private ObservableCollection<AudioSource> _audioSources;

        private string _searchString = string.Empty;

        private double _playerPosition;

        private Pages _currentPage;

        private MediaPlayer _player;

        private readonly TaskbarIcon _notifyIcon;

        private readonly Stack<Audio> _playedAudios = new Stack<Audio>();

        private readonly Random _random = new Random(DateTime.Now.Millisecond);

        private readonly Timer _playerPositionTimer = new Timer(750);

        #endregion Fields

        #region Routed Commands

        public static readonly RoutedCommand ButtonCommand = new RoutedCommand("Button", typeof(ElisVKViewModel));

        public static readonly RoutedCommand ListBoxCommand = new RoutedCommand("ListBox", typeof(ElisVKViewModel));

        public static readonly RoutedCommand AddCommand = new RoutedCommand("Add", typeof(ElisVKViewModel));

        public static readonly RoutedCommand RemoveCommand = new RoutedCommand("Remove", typeof(ElisVKViewModel));

        public static readonly RoutedCommand SearchCommand = new RoutedCommand("Search", typeof(ElisVKViewModel));

        #endregion Routed Commands

        #region Constructors

        static ElisVKViewModel()
        {
             
        }

        public ElisVKViewModel(UIElement view, TaskbarIcon notifyIcon)
        {
            if (view != null)
            {
                view.CommandBindings.Add(new CommandBinding(ButtonCommand, OnButtonCommand));
                view.CommandBindings.Add(new CommandBinding(ListBoxCommand, OnListBoxCommand));
                view.CommandBindings.Add(new CommandBinding(AddCommand, OnAddCommand));
                view.CommandBindings.Add(new CommandBinding(RemoveCommand, OnRemoveCommand));
                view.CommandBindings.Add(new CommandBinding(SearchCommand, OnSearchCommand));
            }

            if (notifyIcon != null)
            {
                _notifyIcon = notifyIcon;
                _notifyIcon.TrayToolTipOpen += NotifyIconOnTrayToolTipOpen;
                
                var balloon = App.WindowUI.GetUserControl("BalloonView");
                balloon.DataContext = new BalloonViewModel(this, NotificationActions.Play);

                _notifyIcon.TrayToolTip = balloon;
            }

            Initialize();
        }

        private void NotifyIconOnTrayToolTipOpen(object sender, RoutedEventArgs e)
        {
            var balloon = ((UserControl ) _notifyIcon.TrayToolTip).DataContext as BalloonViewModel;

            if (balloon != null)
                balloon.Action = NotificationActions.Info;
        }

        #endregion

        #region Properties

        public bool IsPlaying
        {
            get
            {
                return _isPlaying;
            }

            set
            {
                if (_isPlaying != value)
                {
                    _isPlaying = value;
                    _playerPositionTimer.Enabled = value;

                    OnPropertyChanged("IsPlaying");
                }
            }
        }

        public bool IsShuffleOn
        {
            get
            {
                return _isShuffleOn;
            }

            set
            {
                if (_isShuffleOn != value)
                {
                    _isShuffleOn = value;

                    OnPropertyChanged("IsShuffleOn");
                }
            }
        }
        
        public ObservableCollection<Audio> Audios
        {
            get
            {
                return _audios;
            }

            set
            {
                if (_audios != value)
                {
                    _audios = value;

                    OnPropertyChanged("Audios");
                }
            }
        }

        public Audio SelectedAudio
        {
            get
            {
                if (_selectedAudio == null)
                {
                    _selectedAudio = Audios == null || Audios.Count == 0 ? null : Audios[0];
                }

                return _selectedAudio;
            }

            set
            {
                if (_selectedAudio != value)
                {
                    _selectedAudio = value;

                    OnPropertyChanged("SelectedAudio");
                }
            }
        }

        public string SearchString
        {
            get
            {
                return _searchString;
            }

            set
            {
                if (_searchString != value)
                {
                    _searchString = value;

                    OnPropertyChanged("SearchString");
                }
            }
        }

        public Visibility SearchControlVisibility
        {
            get { return Visibility.Visible; }
        }

        public MediaPlayer Player
        {
            get
            {
                if (_player == null)
                {
                    _player = new MediaPlayer();

                    _player.MediaEnded += OnMediaEnded;
                }

                return _player;
            }
        }

        public TaskbarIcon NotifyIcon
        {
            get
            {
                return _notifyIcon;
            }
        }

        public AudioSource AudioSource
        {
            get
            {
                if (_audioSource == null)
                    _audioSource = AudioSources[0];

                return _audioSource;
            }

            set
            {
                if (value != _audioSource)
                {
                    _audioSource = value;

                    if (Audios != null && Audios.Count > 0)
                        Audios.Clear();

                    RefreshAudioList();

                    OnPropertyChanged("AudioSource");
                    OnPropertyChanged("SearchControlVisibility");
                }
            }
        }

        public ObservableCollection<AudioSource> AudioSources
        {
            get
            {
                if (_audioSources == null || _audioSources.Count == 0)
                    InitializeAudioSources();

                return _audioSources;
            }
        }

        public double Volume
        {
            get
            {
                return Player.Volume;
            }

            set
            {
                if (value != Player.Volume)
                {
                    Player.Volume = value;

                    OnPropertyChanged("Volume");
                }
            }
        }

        public double PlayerPosition
        {
            get
            {
                if (Player.Source == null || !Player.NaturalDuration.HasTimeSpan)
                    return (_playerPosition = 0);

                if (Player.NaturalDuration.TimeSpan.Ticks == 0) 
                    return (_playerPosition = 0);

                _playerPosition = (double) Player.Position.Ticks / Player.NaturalDuration.TimeSpan.Ticks;

                return _playerPosition;
            }

            set
            {
                if (_playerPosition == value)
                    return;

                _playerPosition = value;
                Player.Position = new TimeSpan((long) (_playerPosition * Player.NaturalDuration.TimeSpan.Ticks));
                
                OnPropertyChanged("PlayerPosition");
            }
        }

        public Pages CurrentPage
        {
            get
            {
                return _currentPage;
            }

            set
            {
                if (value == _currentPage)
                    return;

                _currentPage = value;
                OnPropertyChanged("CurrentPage");
            }
        }

        public Settings Settings
        {
            get
            {
                return App.Settings;
            }
        }

        private Stack<Audio> PlayedAudios
        {
            get
            {
                return this._playedAudios;
            }
        }

        #endregion

        #region Public methods

        public void Dispose()
        {
            App.Settings.HotKeys.Dispose();
        }

        public void RefreshAudioList()
        {
            try
            {
                //switch (AudioSource)
                //{
                //    case AudioSource.My_Music:
                //        {
                //            var buff = WebClient.DownloadData(
                //                "https://api.vkontakte.ru/method/audio.get.xml?access_token=" + App.SessionInfo.AccessToken);

                //            Audios = new ObservableCollection<Audio>(VKHelper.ParseAudiosFromXML(Encoding.UTF8.GetString(buff)));
                //        }
                //        break;
                //    case AudioSource.Recommendations:
                //        {
                //            var page = PostRequest("http://vkontakte.ru/audio?act=recommendations", App.SessionInfo.Cookie);

                //            Audios = new ObservableCollection<Audio>(Audio.ParseRecommendationsPost(page));
                //        }
                //        break;
                //    case AudioSource.Popular:
                //        {
                //            var page = PostRequest("http://vkontakte.ru/audio?act=popular", App.SessionInfo.Cookie);

                //            Audios = new ObservableCollection<Audio>(Audio.ParseRecommendationsPost(page));
                //        }
                //        break;
                //    case AudioSource.Friends:
                //        {
                //            if (Friend == null || Friend.UserID == 0)
                //            {
                //                return;
                //            }

                //            var buff = WebClient.DownloadData(
                //                string.Format("https://api.vkontakte.ru/method/audio.get.xml?uid={0}&access_token={1}", Friend.UserID,  App.SessionInfo.AccessToken));

                //            Audios = new ObservableCollection<Audio>(VKHelper.ParseAudiosFromXML(Encoding.UTF8.GetString(buff)));
                //        }
                //        break;
                //    case AudioSource.Search:
                //        {
                //            if (string.IsNullOrEmpty(SearchString))
                //                Audios.Clear();

                //            var data = Encoding.UTF8.GetString(WebClient.DownloadData(string.Format(
                //                                "https://api.vkontakte.ru/method/audio.search.xml?q=\"{0}\"&count=200&access_token={1}", SearchString, App.SessionInfo.AccessToken)));

                //            Audios = new ObservableCollection<Audio>(VKHelper.ParseAudiosFromXML(data));
                //        }
                //        break;
                //    default:
                //        throw new NotImplementedException();
                //}

                if (string.IsNullOrEmpty(SearchString))
                {
                    Audios = AudioSource.GetAudios();
                }
                else
                {
                    Audios.Clear();

                    var data = Encoding.UTF8.GetString(VKHelper.DownloadData(string.Format(
                                        "https://api.vkontakte.ru/method/audio.search.xml?q=\"{0}\"&count=200&access_token={1}", SearchString, App.SessionInfo.AccessToken)));

                    Audios = new ObservableCollection<Audio>(VKHelper.ParseAudiosFromXML(data));
                }

                IsPlaying = false;
                Player.Stop();
                this.PlayedAudios.Clear();
            }
            catch
            {

            }
        }

        #endregion

        #region Protected methods

        #endregion Protected methods

        #region Private methods

        private void InitializeAudioSources()
        {
            AudioSource.ElisVKViewModel = this;

            _audioSources = new ObservableCollection<AudioSource>
                                {
                                    new VKMyMusicAudioSource(),
                                    new VKRecommendationsAudioSource(),
                                    new VKPopularAudioSource(),
                                    new VKFriendsAudioSource(),
                                    new VKGroupsAudioSource(),
                                    new VKSubscriptionsAudioSource()
                                };

            if (!string.IsNullOrEmpty(App.Settings.Bookmarks))
                _audioSources.Add(new VKBookmarksAudioSource(App.Settings.Bookmarks));
        }
        
        private void Initialize()
        {
            if (App.Settings.UseHotKeys)
                App.Settings.HotKeys.RegAllHotKeys(HotKeyPressed);

            if (string.IsNullOrEmpty(App.Settings.SynchronizationPath))
            {
                App.Settings.SynchronizationPath = Path.GetTempPath();
                App.SaveSettings();
            }

            Player.ScrubbingEnabled = true;

            _playerPositionTimer.AutoReset = true;
            _playerPositionTimer.Elapsed += delegate
                {
                    OnPropertyChanged("PlayerPosition");
                };
        }

        private Audio EnsureAudioInfoFilled(Audio audioToCheck)
        {
            if (audioToCheck.AudioID != 0)
                return audioToCheck;

            var data = Encoding.UTF8.GetString(VKHelper.DownloadData(string.Format(
                            "https://api.vkontakte.ru/method/audio.search.xml?q=\"{0} - {1}\"&auto_complete=0&count=200&access_token={2}", audioToCheck.Artist, audioToCheck.Title, App.SessionInfo.AccessToken)));

            var audioToAddList = VKHelper.ParseAudiosFromXML(data);

            if (audioToAddList == null || audioToAddList.Count == 0)
                return audioToCheck;

            foreach (var audio in audioToAddList)
            {
                if (audioToCheck.IsEqual(audio))
                {
                    return audio;
                }
            }

            return audioToAddList[0];
        }

        private void OnButtonCommand(object sender, ExecutedRoutedEventArgs e)
        {
            DoAction(e.Parameter.ToString());
        }

        private void OnListBoxCommand(object sender, ExecutedRoutedEventArgs e)
        {
            PlayAudio(SelectedAudio);
        }

        private void OnAddCommand(object sender, ExecutedRoutedEventArgs e)
        {
            if (AudioSource is VKMyMusicAudioSource)
                return;

            var audios = e.Parameter as IList<object>;

            if (audios == null)
                return;

            var audiosToAdd = new List<Audio>(audios.Count);

            audiosToAdd.AddRange(audios.OfType<Audio>());

            foreach (var audio in audiosToAdd)
            {
                var audioToAdd = EnsureAudioInfoFilled(audio);
                
                VKHelper.DownloadData(string.Format(
                                "https://api.vkontakte.ru/method/audio.add.xml?aid={0}&oid={1}&access_token={2}", audioToAdd.AudioID, audioToAdd.OwnerID, App.SessionInfo.AccessToken));
            }
        }

        private void OnRemoveCommand(object sender, ExecutedRoutedEventArgs e)
        {
            var audios = e.Parameter as IList<object>;

            if (audios == null)
                return;

            var audiosToDelete = new List<Audio>(audios.Count);
            
            audiosToDelete.AddRange(audios.OfType<Audio>());

            foreach (var audio in audiosToDelete)
            {
                var audioToDelete = EnsureAudioInfoFilled(audio);

                VKHelper.DownloadData(string.Format(
                                "https://api.vkontakte.ru/method/audio.delete.xml?aid={0}&oid={1}&access_token={2}", audioToDelete.AudioID, audioToDelete.OwnerID, App.SessionInfo.AccessToken));
                
                Audios.Remove(audio);
            }
        }

        private void OnSearchCommand(object sender, ExecutedRoutedEventArgs e)
        {
            RefreshAudioList();
        }

        private void OnMediaEnded(object sender, EventArgs eventArgs)
        {
            SelectedAudio = GetNextSong();
            PlayAudio(SelectedAudio);
        }

        private Audio GetNextSong()
        {
            Audio audio = null;

            if (Audios == null || Audios.Count == 1) 
                return null;

            if (!IsShuffleOn)
            {
                var index = Audios.IndexOf(SelectedAudio);
                audio =  index >= Audios.Count ? Audios[0] : Audios[index + 1];
            }
            else
            {
                if (PlayedAudios.Count == Audios.Count)
                    PlayedAudios.Clear();

                do
                {
                    audio = Audios[_random.Next(0, Audios.Count - 1)];
                }
                while (PlayedAudios.Contains(audio) || SelectedAudio == audio);
            }

            PlayedAudios.Push(audio);
            return audio;
        }

        private void PlayAudio(Audio audio)
        {
            if (audio == null)
                return;

            SelectedAudio = audio;

            Player.Stop();
            Player.Open(new Uri(audio.DownloadURL));
            Player.Play();
            IsPlaying = true;
            //NotifyIcon.ShowBalloonTip("Playing", SelectedAudio.ToString(), BalloonIcon.Info);
            ShowNotification(NotificationActions.Play);
        }

        private void DoAction(string action)
        {
            switch (action)
            {
                case "Play":
                    {
                        if (IsPlaying)
                            break;

                        if (Player.Source == null)
                        {
                            PlayAudio(GetNextSong());
                            break;
                        }

                        Player.Play();
                        ShowNotification(NotificationActions.Play);
                    }
                    break;
                case "Play/Pause":
                    {
                        if (IsPlaying)
                        {
                            IsPlaying = false;
                            Player.Pause();
                            break;
                        }

                        if (Player.Source == null || string.Compare(Player.Source.AbsoluteUri, SelectedAudio.DownloadURL, true) != 0)
                        {
                            PlayAudio(GetNextSong());
                            break;
                        }

                        Player.Play();
                        IsPlaying = true;
                    }
                    break;
                case "Pause":
                    {
                        Player.Pause();
                        IsPlaying = false;
                        ShowNotification(NotificationActions.Pause);
                    }
                    break;
                case "Previous":
                    {
                        if (PlayedAudios.Count == 0)
                            break;

                        PlayAudio(PlayedAudios.Pop());
                    }
                    break;
                case "Next":
                    {
                        PlayAudio(GetNextSong());
                    }
                    break;
                case "Volume Up":
                    {
                        Player.Volume = Player.Volume >= 0.95 ? 1 : Player.Volume + 0.05;
                        OnPropertyChanged("Volume");
                        ShowNotification(NotificationActions.Volume);
                    }
                    break;
                case "Volume Down":
                    {
                        Player.Volume = Player.Volume <= 0.05 ? 0 : Player.Volume - 0.05;
                        OnPropertyChanged("Volume");
                        ShowNotification(NotificationActions.Volume);
                    }
                    break;
                case "Add":
                    {
                        if (AudioSource is VKMyMusicAudioSource)
                            return;

                        var audio = EnsureAudioInfoFilled(SelectedAudio);
                        
                        VKHelper.DownloadData(string.Format(
                                "https://api.vkontakte.ru/method/audio.add.xml?aid={0}&oid={1}&access_token={2}", audio.AudioID, audio.OwnerID, App.SessionInfo.AccessToken));
                    }
                    break;
                case "Remove":
                    {
                        VKHelper.DownloadData(string.Format(
                                "https://api.vkontakte.ru/method/audio.delete.xml?aid={0}&oid={1}&access_token={2}", SelectedAudio.AudioID, SelectedAudio.OwnerID, App.SessionInfo.AccessToken));

                        if (AudioSource is VKMyMusicAudioSource)
                            Audios.Remove(SelectedAudio);
                    }
                    break;
                case "Refresh":
                    {
                        RefreshAudioList();
                    }
                    break;
                case "Shuffle":
                    {
                        IsShuffleOn = !IsShuffleOn;
                    }
                    break;
                case "Settings":
                    {
                        CurrentPage = Pages.SettingsPage;
                    }
                    break;
                case "Synchronize":
                    {
                        AudioSource.Synchronize();
                    }
                    break;
                case "MainPage":
                    {
                        CurrentPage = Pages.MainPage;
                    }
                    break;
                case "SaveSettings":
                    {
                        App.SaveSettings();
                    }
                    break;
            }
        }

        private void ShowNotification(NotificationActions action)
        {
            var balloonUserControl = App.WindowUI.GetUserControl("BalloonView");
            balloonUserControl.DataContext = new BalloonViewModel(this, action);
            
            NotifyIcon.ShowCustomBalloon(balloonUserControl, PopupAnimation.Slide, 3000);
        }

        #region SystemHotKey  
        
        private void HotKeyPressed(HotKey hotKey)
        {
            DoAction(hotKey.Name);
        }
        
        #endregion SystemHotKey


        #endregion Private methods

        
    }
}
